/*
 *  hellApp.m
 *  touchhell
 *
 *  Created by omega on 08/12/22.
 *  Copyright 2008 __MyCompanyName__. All rights reserved.
 *
 */

#import <OpenGLES/ES1/gl.h>
#import "string.h"

#import "touchHell.h"
#import "hellApp.h"

#import "EAGLView.h"
#import "math.h"

#define PLAYER_GRAB_RANGE	32.0f
#define PLAYER_MAX			12
#define PLAYER_SPEED_MAX	16.0f
#define PLAYER_SIZE_MIN		16.0f
#define PLAYER_SIZE_MAX		256.0f

#define WALL_BOUND_SOUND_THREASHOLD	4.0f
#define PLAYER_COLLISION_SOUND_THREASHOLD	2.0f

#define WALL_BOUND_FACTOR	-0.9f

#define GRAB_NOGRAB			-1

int play_timer;
float accelerate_x , accelerate_y , accelerate_z;

typedef struct{
	float x,y,r;
	float vx,vy,vr;
	float size;
	int anime_timer;
	bool alive;
} Player;
Player player[PLAYER_MAX];
int grab_idx;
bool isPlayBGM;

void Hell_initLoad(){
	srand(time(NULL));
	int bg = (int)((rand()/53) % 10) + 1;
	char bg_name[255];
	sprintf( bg_name , "%02d.png" , bg );
	
	Hell_loadTextureFromFile( HELL_TEXTURE_FONT, "font.png" );
	Hell_loadTextureFromFile( HELL_TEXTURE_ICON, /*"hell_icon.png"*/"chabu.png" );
	Hell_loadTextureFromFile( HELL_TEXTURE_BACKGOUND , bg_name );
	
	Hell_loadSoundEffectFromFile( HELL_SOUND_JUMP, "jump.wav" );
	Hell_loadSoundEffectFromFile( HELL_SOUND_JUMP2, "jump2_small.wav" );
	
	isPlayBGM = NO;
	
	for(int i=0;i<PLAYER_MAX;i++){
		Player *p = &player[i];
		p->x = (float)rand() / RAND_MAX * 320.0f - 160.f;
		p->y = (float)rand() / RAND_MAX * 320.0f - 160.f;
		p->vx = (float)rand() / RAND_MAX * 2.0f - 1.0f;
		p->vy = (float)rand() / RAND_MAX * 2.0f - 1.0f;
		p->r = (float)rand() / RAND_MAX * 2.0f - 1.0f;
		p->vr = (float)rand() / RAND_MAX * 2.0f - 1.0f;
		p->alive = YES;
		p->size = 24.0f;
	}
	grab_idx = GRAB_NOGRAB;
	play_timer = 0;
	accelerate_x = accelerate_y = accelerate_z = 0;
	
}

void Hell_terminate(){
}

void Hell_update(){
	play_timer++;
	
	accelerate_x = Hell_getAccelerometerX();
	accelerate_y = Hell_getAccelerometerY();
	accelerate_z = Hell_getAccelerometerZ();
	for(int i=0;i<PLAYER_MAX;i++){
		Player *p = &player[i];
		
		if( grab_idx != i ){
			p->x += p->vx;
			p->y += p->vy;
		}
		
		p->vx *= 0.99f;
		p->vy *= 0.99f;
		p->vx += accelerate_x * 0.8f;
		p->vy += accelerate_y * 0.8f;
		p->r += p->vr;
		if( fabs(p->vx) < 0.01f && fabs(p->vy) < 0.01f ){
			p->vx = p->vy = 0;
		}
		
		if( p->vx * p->vx + p->vy * p->vy > PLAYER_SPEED_MAX * PLAYER_SPEED_MAX ){
			float sp = sqrt( p->vx * p->vx + p->vy * p->vy );
			p->vx = p->vx / sp * PLAYER_SPEED_MAX;
			p->vy = p->vy / sp * PLAYER_SPEED_MAX;
		}
		
		// bound on wall
		bool is_bound_sound = false;
		if( p->x >  160.0f - p->size ) {
			if( p->vx > 0 ) p->vx *= WALL_BOUND_FACTOR;
			if( fabs( p->vx ) > WALL_BOUND_SOUND_THREASHOLD ) is_bound_sound = true;
			p->x =  160.0f - p->size;
		}
		if( p->x < -160.0f + p->size ) {
			if( p->vx < 0 ) p->vx *= WALL_BOUND_FACTOR;
			if( fabs( p->vx ) > WALL_BOUND_SOUND_THREASHOLD ) is_bound_sound = true;
			p->x = -160.0f + p->size;
		}
		if( p->y >  240.0f - p->size ) {
			if( p->vy > 0 ) p->vy *= WALL_BOUND_FACTOR;
			if( fabs( p->vy ) > WALL_BOUND_SOUND_THREASHOLD ) is_bound_sound = true;
			p->y =  240.0f - p->size;
		}
		if( p->y < -240.0f + p->size ) {
			if( p->vy < 0 ) p->vy *= WALL_BOUND_FACTOR;
			if( fabs( p->vy ) > WALL_BOUND_SOUND_THREASHOLD ) is_bound_sound = true;
			p->y = -240.0f + p->size;
		}
		
		if( is_bound_sound ) Hell_playSoundEffect( HELL_SOUND_JUMP );
		
		// collision
		for(int j=i+1;j<PLAYER_MAX;j++){
			Player *p2 = &player[j];
			float dx = p2->x - p->x;
			float dy = p2->y - p->y;
			if( dx * dx + dy * dy < (p2->size + p->size)*(p2->size + p->size) ){
				if( (p->vx - p2->vx)*(p->vx - p2->vx) + (p->vy - p2->vy)*(p->vy - p2->vy) > PLAYER_COLLISION_SOUND_THREASHOLD * PLAYER_COLLISION_SOUND_THREASHOLD ){
					Hell_playSoundEffect( HELL_SOUND_JUMP2 );
				}
				float dist = sqrt(dx * dx + dy * dy);
				float ux = dx / dist;
				float uy = dy / dist;
				
				p->x -= (p2->size + p->size - dist) * ux;
				p->y -= (p2->size + p->size - dist) * uy;
				p2->x += (p2->size + p->size - dist) * ux;
				p2->y += (p2->size + p->size - dist) * uy;
				
				float g_vx = (p2->vx * p2->size + p->vx * p->size) / (p2->size + p->size);
				float g_vy = (p2->vy * p2->size + p->vy * p->size) / (p2->size + p->size);
				
				float o_vx = p2->vx - g_vx;
				float o_vy = p2->vy - g_vy;
				
				float vp = fabs( o_vx * ux + o_vy * uy );
				float bound_factor = 0.8f;
				p2->vx = p2->vx + (vp * ux * 2.0f * bound_factor);
				p2->vy = p2->vy + (vp * uy * 2.0f * bound_factor);
				p->vx = p->vx - (vp * ux * 2.0f * bound_factor);
				p->vy = p->vy - (vp * uy * 2.0f * bound_factor);
			}
		}
	}
}

void Hell_draw(){
	char strbuf[1024];
	int i;
	
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrthof(-160.0f, 160.0f, -240.0f, 240.0f, -1.0f, 1.0f);
    glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	
//	glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT);
	
	glEnable(GL_BLEND);	
	glEnable(GL_TEXTURE_2D);
	glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
	glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
	glEnableClientState(GL_VERTEX_ARRAY);
	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
	
	Hell_drawTexture( HELL_TEXTURE_BACKGOUND, 0 , 0 , 320.0f , 480.0f);

	/*
	for(i=0;i<PLAYER_MAX;i++){
		glPushMatrix();
		{
			sprintf( strbuf , "%02d X:%03.1f Y:%03.1f VX:%02.2f VY:%02.2f" , i , player_x[i] , player_y[i] , player_vx[i] , player_vy[i] );
			glTranslatef( -160.0f + 4.0f , +240.0f - 4.0f -8.0f * i ,0 );
			Hell_drawFontWithTexture( HELL_TEXTURE_FONT, strbuf );
		}
		glPopMatrix();
	}
	*/
	for(i=0;i<PLAYER_MAX;i++){
		Player *p = &player[i];
		glPushMatrix();
		{
			glTranslatef( p->x , p->y , 0 );
			glRotatef(p->r , 0.0f ,  0.0f , 1.0f);
			glScalef( p->size / 24.0f , p->size / 24.0f, 0.5f );
			Hell_drawTexture( HELL_TEXTURE_ICON , 0,0,64.0f,64.0f);
		}
		glPopMatrix();
	}	
	glPushMatrix();
	{
		sprintf( strbuf , "AX:%.2f AY:%.2f AZ:%.2f" , accelerate_x , accelerate_y , accelerate_z );
		glTranslatef( -160.0f + 4.0f , -240.0f + 4.0f ,0 );
		Hell_drawFontWithTexture( HELL_TEXTURE_FONT, strbuf );
	}
	glPopMatrix();
}

int getNearestPlayerIndex( float x , float y ){
	int idx = -1;
	float dist = 9999999.0f;
	for(int t=0;t<PLAYER_MAX;t++){
		float dx = player[t].x - x;
		float dy = player[t].y - y;
		float d = dx * dx + dy * dy;
		if( d < dist ){
			dist = d;
			idx = t;
		}
	}
	return idx;
}

float get2DVectorDistanceSquare( float x1 , float y1 , float x2 , float y2 ){
	return (x1 - x2)*(x1 - x2) + (y1 - y2)*(y1 - y2);
}

Hell_TouchEvent medianTouchEvent( Hell_TouchEvent* touchevents , int eventCount ){
	Hell_TouchEvent ev;
	ev.prev_x = 0;
	ev.prev_y = 0;
	ev.x = 0;
	ev.y = 0;
	for(int t=0;t<eventCount;t++){
		ev.prev_x += touchevents[t].prev_x;
		ev.prev_y += touchevents[t].prev_y;
		ev.x += touchevents[t].x;
		ev.y += touchevents[t].y;
	}
	ev.prev_x /= eventCount;
	ev.prev_y /= eventCount;
	ev.x /= eventCount;
	ev.y /= eventCount;
	return ev;
}

void Hell_callbackTouchBegan( Hell_TouchEvent* touchevents , int eventCount ){
	Hell_TouchEvent ev = medianTouchEvent( touchevents , eventCount );
	int nearest_idx = getNearestPlayerIndex( ev.x , ev.y );
	float dist = get2DVectorDistanceSquare( ev.x , ev.y , player[nearest_idx].x , player[nearest_idx].y );
	float size = (player[nearest_idx].size > PLAYER_GRAB_RANGE) ? player[nearest_idx].size : PLAYER_GRAB_RANGE;
	
	if( dist < size * size ){
		grab_idx = nearest_idx;
		player[grab_idx].x = ev.x;
		player[grab_idx].y = ev.y;
	}else{
		grab_idx = GRAB_NOGRAB;
	}
	/*
	if( eventCount > 0 ){
		if( isPlayBGM ){
			Hell_stopBgm();
			isPlayBGM = NO;
		}else{
			Hell_loadBgm( "128_C_002.aac" );
			Hell_setBgmVolume( 0.5 );
			Hell_playBgm();
			isPlayBGM = YES;
		}
	}
	 */
}

void Hell_callbackTouchMoved( Hell_TouchEvent* touchevents , int eventCount ){
	// 拡大縮小量
	float size_add = 0;
	if(eventCount > 1){
		float o_dx = touchevents[0].prev_x - touchevents[1].prev_x;
		float o_dy = touchevents[0].prev_y - touchevents[1].prev_y;
		float o_dist = sqrt( o_dx * o_dx + o_dy * o_dy );
		
		float dx = touchevents[0].x - touchevents[1].x;
		float dy = touchevents[0].y - touchevents[1].y;
		float dist = sqrt( dx * dx + dy * dy );
		
		size_add = dist - o_dist;
	}
	
	// つかむ
	Hell_TouchEvent ev = medianTouchEvent( touchevents , eventCount );
	int nearest_idx = getNearestPlayerIndex( ev.prev_x , ev.prev_y );
	float dist = get2DVectorDistanceSquare( ev.prev_x , ev.prev_y , player[nearest_idx].x , player[nearest_idx].y );
	float size = (player[nearest_idx].size > PLAYER_GRAB_RANGE) ? player[nearest_idx].size : PLAYER_GRAB_RANGE;

	if( dist < size * size ){
		grab_idx = nearest_idx;
		player[grab_idx].vx = ev.x - ev.prev_x;
		player[grab_idx].vy = ev.y - ev.prev_y;
		player[grab_idx].x = ev.x;
		player[grab_idx].y = ev.y;
		player[grab_idx].size += size_add;
		if( player[grab_idx].size < PLAYER_SIZE_MIN ) player[grab_idx].size = PLAYER_SIZE_MIN;
		if( player[grab_idx].size > PLAYER_SIZE_MAX ) player[grab_idx].size = PLAYER_SIZE_MAX;
	}else{
		grab_idx = GRAB_NOGRAB;
	}
}

void Hell_callbackTouchEnded( Hell_TouchEvent *touchevents , int eventCount ){
	grab_idx = GRAB_NOGRAB;
}
